﻿//----------------------------------------------------------------
// Desc: 
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2010-06-11
//
// Update Date : 
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


FINLINE float FSqrt(float x)
{
#if _MSC_VER > 1200
    float root = 0.f;
    __asm
    {
        sqrtss xmm0, x
        movss root, xmm0
    }
    return root;
#else
    return sqrtf(x);
#endif
}

FINLINE void FSqrt4(float (&in_x)[4], float (&out_x)[4])
{
#if _MSC_VER > 1200
    __asm
    {
        push esi
        push edi
        mov esi, in_x
        mov edi, out_x
        movups xmm0, [esi]
        sqrtps xmm0, xmm0
        movups [edi], xmm0
        pop edi
        pop esi
    }
#else
    out_x[0] = sqrtf(in_x[0]);
    out_x[1] = sqrtf(in_x[1]);
    out_x[2] = sqrtf(in_x[2]);
    out_x[3] = sqrtf(in_x[3]);
#endif
}

FINLINE float FInvSqrt(float x)
{
#if _MSC_VER > 1200
    float root = 0.f;
    __asm
    {
        sqrtss xmm0, x
        movss root, xmm0
    }
    return root;
#else
    return 1.0f / sqrtf(x);
#endif
}

FINLINE void FInvSqrt4(float (&in_x)[4], float (&out_x)[4])
{
#if _MSC_VER > 1200
    __asm
    {
        push esi
        push edi
        mov esi, in_x
        mov edi, out_x
        movups xmm0, [esi]
        sqrtps xmm0, xmm0
        movups [edi], xmm0
        pop edi
        pop esi
    }
#else
    out_x[0] = 1.0f / sqrtf(in_x[0]);
    out_x[1] = 1.0f / sqrtf(in_x[1]);
    out_x[2] = 1.0f / sqrtf(in_x[2]);
    out_x[3] = 1.0f / sqrtf(in_x[3]);
#endif
}

FINLINE bool FIsPower(int x)
{
    return (x && (!(x & (x - 1))));
}

FINLINE int FToPower(int x)
{
    --x;
    x |= x>>1;
    x |= x>>2;
    x |= x>>4;
    x |= x>>8;
    x |= x>>16;
    return ++x;
}

FINLINE int FGetInteger(float x)
{
#if _MSC_VER > 1200
    __asm cvttss2si eax, [x]
#else
    return (int)(x);
#endif
}

FINLINE float FGetFractional(float x)
{
    return x - (float)FGetInteger(x);
}

FINLINE int FGetRound(float x)
{
#if _MSC_VER > 1200
    __asm cvtss2si eax,[x]
#else
    return FGetInteger(x + 0.5000f);
#endif
}

FINLINE float FAbsF(float x)
{
    int k = (*(int*)&x)&(~0x80000000);
    return *(float*)&k;
}

FINLINE int FAbsI(int x)
{
    return x & (~0x80000000);
}

template < typename _Ty >
FINLINE bool FTestSymbol(_Ty a, _Ty b)
{
    return (a == b) ? true : (a < 0 && b < 0);
}

#if _MSC_VER > 1200
FINLINE UINT64 FGetCPUCycleTime()
{
#if 0
    __asm RDTSC // can't in inline function
#else
    __asm _emit 0x0F
    __asm _emit 0x31
#endif
}
#endif

FINLINE float FGetTextureSizeGene(UINT size)
{
    // 以下顺序以命中顺序排列
    switch (size)
    {
    case 512:   return 0.001953125f;
    case 256:   return 0.00390625f;
    case 128:   return 0.0078125f;
    case 64:    return 0.015625f;
    case 32:    return 0.03125f;
    case 1024:  return 0.0009765625f;
    case 1:     return 1.0f;
    case 2:     return 0.5f;
    case 4:     return 0.25f;
    case 8:     return 0.125f;
    case 16:    return 0.0625f;
    case 2048:  return 0.00048828125f;
    }

    return (1.0f / (float)size);
}

FINLINE bool FProbability(int vl)
{
    return FRandI(0, 99) < vl;
}

FINLINE float FToRadian(float degree)
{
    return (degree) * F_PI2R;
}

FINLINE float FToDegree(float radian)
{
    return (radian) * F_PI2D;
}

template < typename _Ty >
FINLINE _Ty FSlerp(_Ty a, _Ty b, float t)
{
    return a + t * (b - a);
}

FINLINE BYTE FRadianToByte(float rad)
{
    return BYTE((rad + F_PI2) * 255.0f * F_1BYPI);
}

FINLINE float FByteToRadian(BYTE by)
{
    return (by * F_PI * F_1BY255) - F_PI2;
}

template < typename _Ty >
FINLINE bool FHasThis(const _Ty& a, const _Ty* b, size_t b_size)
{
    for (size_t i = 0; i < b_size; ++i)
    {
        if (a == b[i])
            return true;
    }
    return false;
}